<template>
  <div id="wrap" style="height: 600px">
    <el-card style="width: 100%">
      <el-form
        :inline="true"
        :model="form"
        style="display: flex; align-items: center"
      >
        <el-form-item label="用户名" style="margin-right: 20px">
          <el-input
            v-model="form.username"
            placeholder="请输入用户名"
            clearable
          ></el-input>
        </el-form-item>

        <el-form-item label="密码" style="margin-right: 20px">
          <el-input
            v-model="form.password"
            placeholder="请输入密码"
            show-password
            clearable
          ></el-input>
        </el-form-item>

        <el-form-item style="margin-left: auto">
          <el-button type="primary" @click="connect">登录</el-button>
          <el-button type="danger" @click="disConnect">退出</el-button>
          <el-button type="info" @click="showServerConfig"
            >服务器配置</el-button
          >
        </el-form-item>
      </el-form>
    </el-card>
    <el-card
      id="serverConfigId"
      v-if="serverConfigVisible"
      style="
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-top: 20px;
      "
    >
      <div style="display: flex; align-items: center">
        <span style="width: 80px; text-align: right; margin-right: 10px"
          >服务器IP</span
        >
        <el-input
          v-model="serverIp"
          id="serverIp"
          placeholder="服务IP"
          style="width: 200px"
        ></el-input>
      </div>

      <div style="display: flex; align-items: center">
        <span style="width: 80px; text-align: right; margin-right: 10px"
          >端口号</span
        >
        <el-input
          v-model="port"
          id="port"
          placeholder="端口"
          style="width: 200px"
        ></el-input>
      </div>
    </el-card>

    <el-card style="margin-top: 20px">
      <h2>聊天记录</h2>
      <el-row style="margin-top: 20px">
        <el-col :span="8" style="text-align: left">
          <el-button type="primary" @click="clearLogs">清空记录</el-button>
        </el-col>
        <el-col :span="8">
          <el-button type="primary" @click="authCmd">鉴权命令</el-button>
        </el-col>
        <el-col :span="8">
          <el-button type="primary" @click="heartbeatCmd">心跳命令</el-button>
        </el-col>
      </el-row>

      <el-row>
        <el-col :span="11">
          <div
            style="
              display: flex;
              align-items: center;
              gap: 10px;
              margin-top: 20px;
            "
          >
            <el-button type="primary" @click="friendHistoryCmd">
              获取指定好友历史消息
            </el-button>
            <el-input
              id="history_friend_id"
              placeholder="输入好友ID"
              v-model="historyFriendId"
              clearable
              style="width: 200px"
            ></el-input>
          </div>
        </el-col>
        <el-col :span="12">
          <div
            style="
              display: flex;
              align-items: center;
              gap: 10px;
              margin-top: 20px;
            "
          >
            <el-button type="primary" @click="groupHistoryCmd">
              获取指定群组历史消息
            </el-button>
            <el-input
              id="history_group_id"
              placeholder="输入群组ID"
              v-model="historyGroupId"
              clearable
              style="width: 200px"
            ></el-input>
          </div>
        </el-col>
      </el-row>
    </el-card>

    <div class="content" style="margin-top: 20px">
      <div id="logs" class="chat-container" ref="logDiv">
        <h2>聊天记录</h2>
        <div
          v-for="(item, index) in contentList"
          :key="index"
          class="message-item"
        >
          <!-- 处理系统消息 -->
          <div v-if="item.type === 'system'" class="system-message">
            <div class="system-content">
              {{ item.time }}---{{ item.content }}
            </div>
          </div>
          <!-- 处理历史消息 -->
          <div v-else-if="item.type === 'history'" class="history-divider">
            <span class="divider-line"></span>
            <span class="divider-text">{{ item.content }}</span>
            <span class="divider-line"></span>
          </div>
          <div
            v-else
            class="bubble-wrapper"
            :class="{ 'self-message': item.isSelf }"
          >
            <div class="avatar">
              <img :src="item.avatar" alt="avatar" />
            </div>
            <div class="message-content">
              <div class="username">{{ item.username }}</div>
              <div class="message-bubble">
                <div class="bubble-content">{{ item.content }}</div>
                <div class="time-stamp">{{ formatTime(item.time) }}</div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div id="onlinePanel" class="online">
        <div v-if="groups.length === 0">&nbsp;在线成员(0/0)</div>
        <div v-else>
          <div v-for="group in groups" :key="group.name">
            <div class="group-name">
              &nbsp;{{ group.name }}在线成员({{ group.users.length }}/{{
                group.users.length
              }})
            </div>
            <div
              v-for="user in group.users"
              :key="user.userId"
              :id="user.userId"
              class="user-item"
              @click="onlineDb(user)"
              @mouseover="onlineMove(user)"
              @mouseleave="onlineLeave(user)"
            >
              <img :alt="user.userId" :src="user.avatar" class="user-avatar" />
              <span class="user-info">{{ user.nick }}({{ user.userId }})</span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <el-card class="myContent" style="margin-top: 60px">
      <el-input
        v-model="content"
        id="content"
        style="width: 500px"
        placeholder="请输入内容"
        clearable
      ></el-input>
      <el-button type="primary" @click="sendGroup" style="margin-left: 20px"
        >群聊</el-button
      >
      <el-button type="info" icon="el-icon-message" @click="send">
        私聊{{ sendUser }}
      </el-button>
    </el-card>
  </div>
</template>

<script>
import moment from "moment";
export default {
  data() {
    return {
      form: {
        username: "",
        password: "",
      },
      socket: null,
      serverIp: "localhost", //后台服务IP
      port: "8888", //后台端口
      serverConfigVisible: false,
      content: "",
      historyFriendId: "",
      historyGroupId: "",
      curUser: null,
      friends: [],
      groups: [],
      logs: "",
      onSelected: null,
      sendUser: "",
      contentList: [],
    };
  },
  computed: {
    // 计算总在线成员数
    totalOnlineUsers() {
      return this.curUser.groups.reduce(
        (total, group) => total + group.users.length,
        0
      );
    },
    // 计算总成员数
    totalUsers() {
      return this.totalOnlineUsers; // 假设所有成员都在线
    },
  },
  mounted() {
    this.setUserName();
  },
  methods: {
    /**
     *
     * @param timestamp 格式化时间
     */
    formatTime(timestamp) {
      return new Date(timestamp).toLocaleTimeString();
    },
    connect() {
      if (this.curUser) {
        this.$message.message("当前已登录,请先退出登录!");
        return;
      }
      const ip = this.serverIp;
      const port = this.port;
      const username = this.form.username;
      const password = this.form.password;
      this.socket = new WebSocket(
        `ws:${ip}:${port}?username=${username}&password=${password}`
      );

      this.socket.onopen = () => {
        console.log("ws 连接成功！ ");
        // 连接成功处理
      };

      this.socket.onerror = (e) => {
        this.doSysmessage("异常:" + e, this.formatTime(new Date()));
        this.scrollToBottom();
      };

      this.socket.onclose = (e) => {
        this.curUser = null;
        this.doSysmessage("关闭连接......", this.formatTime(new Date()));
        this.groups = [];
        this.scrollToBottom();
      };

      this.socket.onmessage = (e) => {
        const data = e.data;
        const dataObj = eval("(" + data + ")");

        console.log("消息响应处理=");
        console.log(dataObj);

        if (dataObj.command === 11) {
          //接受到聊天响应处理
          this.COMMAND_CHAT_RESP(dataObj);
        } else if (dataObj.command === 18) {
          //获取用户信息响应处理
          this.COMMAND_GET_USER_RESP(dataObj);
        } else if (dataObj.command === 12 && dataObj.code === 10000) {
          //聊天发送状态
          this.COMMAND_CHAT_RESP_SEND_STATUS(data);
        } else if (dataObj.command === 9) {
          //加入群组的消息通知处理
          this.COMMAND_JOIN_GROUP_NOTIFY_RESP(dataObj);
        } else if (dataObj.command === 10) {
          this.COMMAND_EXIT_GROUP_NOTIFY_RESP(dataObj);
        } else if (dataObj.command === 20 && dataObj.code === 10015) {
          // 获取消息失败处理
          ///获取消息失败，未开启持久化处
        } else if (dataObj.command === 20 && dataObj.code === 10016) {
          /**
           * 处理离线消息
           */
          const msgFlag = "离线消息";
          this.COMMAND_GET_MESSAGE_RESP(dataObj, msgFlag);
        } else if (dataObj.command === 20 && dataObj.code === 10018) {
          /**
           * 处理历史消息
           */
          const msgFlag = "历史消息";
          const msgObj = dataObj.data;
          if (msgObj) {
            this.COMMAND_GET_MESSAGE_RESP(dataObj, msgFlag);
          } else {
            /**
             * 没有历史消息
             */
            this.OTHER(data);
          }
        } else if (dataObj.command === 6) {
          /**
           * 登录命令返回状态处理
           */
          this.COMMAND_LOGIN_RESP(dataObj, data);
        } else {
          this.OTHER(data);
        }
        this.scrollToBottom();
      };
    },
    COMMAND_LOGIN_RESP(dataObj, data) {
      if (dataObj.code === 10007) {
        this.logs += "<font color='green' size='1'>连接成功...</font><br>";
        const userCmd = `{"cmd":17,"type":"0","userId":"${this.form.username}"}`;
        const msgCmd = `{"cmd":19,"type":"0","userId":"${this.form.username}"}`;
        this.socket.send(userCmd);
        this.socket.send(msgCmd);
        this.scrollToBottom();
      } else if (dataObj.code === 10008) {
        this.OTHER(data);
      }
    },
    /**
     * 退出群聊响应
     */
    COMMAND_EXIT_GROUP_NOTIFY_RESP(data) {
      const exitGroupNotify = data.data;
      this.doSysmessage(
        exitGroupNotify.user.nick +
          "(" +
          exitGroupNotify.user.userId +
          ") 退出群聊.....",
        this.formatTime(new Date())
      );

      let onlineUserCmd = {
        cmd: 17,
        type: "0",
        userId: this.curUser.userId,
      };
      this.socket.send(JSON.stringify(onlineUserCmd));
    },
    /**
     *
     * @param data 加入群聊响应
     */
    COMMAND_JOIN_GROUP_NOTIFY_RESP(data) {
      const user = data.user;
      let createTime = this.formatTime(new Date());

      this.doSysmessage("用户：" + user.userId + "加入群聊....", createTime);

      const onlineUserCmd = {
        cmd: 17,
        type: "0",
        userId: user.userId,
      };
      // 获取在线用户列表
      this.socket.send(JSON.stringify(onlineUserCmd));
    },
    COMMAND_JOIN_GROUP_RESP(data) {
      // 成功加入群组响应信息
    },
    COMMAND_CHAT_RESP_SEND_STATUS(data) {
      // 发送成功后的状态处理
    },
    /**
     * 获取聊天室在线用户列表信息
     */
    COMMAND_GET_USER_RESP(data) {
      const user = data.data;

      this.curUser = user;

      //登录用户信息
      // data.data

      //聊天室成员
      //data.data.groups

      //我的好友
      //data.data.friends

      /**
       * 初始化 在线用户信息
       */
      this.initOnlineUsers();
    },
    /**
     * 处理消息响应
     */
    COMMAND_CHAT_RESP(data) {
      const chatObj = data.data;
      console.log("dataObject");
      console.log(chatObj);
      const createTime = moment(chatObj.createTime).format(
        "YYYY/MM/DD HH:mm:ss"
      );
      const from = chatObj.from;
      if (from === this.form.username) {
        /**
         * 处理自己发的消息
         */
        let message = {
          type: "message",
          isSelf: true,
          username: from,
          avatar: this.curUser.avatar,
          content: chatObj.content,
          time: chatObj.createTime,
        };

        this.contentList.push(message);
        return;
      }
      const content = chatObj.content;
      const user = this.getOnlineUserById(from);
      let message = {
        type: "message",
        isSelf: false,
        username: from,
        avatar: this.curUser.avatar,
        content: content,
        time: createTime,
      };

      if (user) {
        /**
         * 查看是否在 聊天群内
         *
         * 可以获取用户信息 【user】
         */
        message.avatar = user.avatar;
      } else {
      }
      this.contentList.push(message);
    },
    /**
     *
     * @param data 处理历史消息
     * @param msgFlag
     */
    COMMAND_GET_MESSAGE_RESP(data, msgFlag) {
      const msgObj = data.data;
      this.friendOfflineMessage(msgObj, msgFlag);
      this.groupOfflineMessage(msgObj, msgFlag);
    },
    /**
     * 好友离线消息处理
     */
    friendOfflineMessage(msgObj, msgFlag) {
    
      const friends = msgObj.friends;
      for (const key in friends) {
        const chatDatas = friends[key];
        for (const index in chatDatas) {
          const user_id = chatDatas[index].from;
          const createTime = moment(chatDatas[index].createTime).format(
            "YYYY/MM/DD HH:mm:ss"
          );
          let message = {
            type: "message",
            isSelf: false,
            username: user_id + " (好友" + msgFlag + "})",
            avatar: 'https://iknow-pic.cdn.bcebos.com/a044ad345982b2b7abc6ee5923adcbef77099bd6',
            content: chatDatas[index].content,
            time: createTime,
          };
          this.contentList.push(message);
        }
      }
    },
    /**
     *群聊离线消息处理
     */
    groupOfflineMessage(msgObj, msgFlag) {
      const groups = msgObj.groups;
      for (const key in groups) {
        const chatDatas = groups[key];
        for (const index in chatDatas) {
          const user_id = chatDatas[index].from;
          const createTime = moment(chatDatas[index].createTime).format(
            "YYYY/MM/DD HH:mm:ss"
          );
          let message = {
            type: "message",
            isSelf: false,
            username:
              user_id + "(群聊[" + chatDatas[index].groupId + "]" + msgFlag,
            avatar: 'https://iknow-pic.cdn.bcebos.com/a044ad345982b2b7abc6ee5923adcbef77099bd6',
            content: chatDatas[index].content,
            time: createTime,
          };
          this.contentList.push(message);
        }
      }
    },
    /**
     * 处理其他消息
     */
    OTHER(data) {
      this.doSysmessage(data, this.formatTime(new Date()));
    },
    getOnlineUserById(id) {
      if (!this.curUser) return;
      const groups = this.curUser.groups;
      for (let g = 0; g < groups.length; g++) {
        const group = groups[g];
        const users = group.users;
        for (let u = 0; u < users.length; u++) {
          const user = users[u];
          if (user.userId === id) {
            return user;
          }
        }
      }
      return null;
    },
    /**
     * 初始化 团队好友信息
     */
    initOnlineUsers() {
      if (this.curUser) {
        /**
         * 聊天室在线好友
         */
        const groups = this.curUser.groups;

        this.groups = groups;
      }
    },
    /**
     * 退出群聊
     */
    disConnect() {
      if (this.socket) {
        this.curUser = null;

        this.groups = [];

        this.socket.close();
      }
    },
    /**
     * 私聊给个人
     */
    send() {
      let toId = "";

      toId = this.onSelected.userId;

      if (this.onSelected) {
        toId = this.onSelected.userId;
      }
      const createTime = new Date().getTime();
      const content = this.content;
      if (!content) return;

      const msg = {
        from: this.form.username,
        to: toId,
        cmd: 11,
        createTime: createTime,
        chatType: "2",
        msgType: "0",
        content: content,
      };
      if (!toId) {
        this.$message.success("请选择要私聊的人！");
        return;
      }
      if (toId === this.form.username) {
        this.$message.success("无法给自己发送消息!");
        return;
      }
      this.socket.send(this.gsh(msg));

      let message = {
        type: "message",
        isSelf: true,
        username: this.curUser.userId,
        avatar: this.curUser.avatar,
        content: content,
        time: createTime,
      };
      this.contentList.push(message);

      this.content = "";
    },
    /**
     * 发送给 团群
     */
    sendGroup() {
      const createTime = new Date().getTime();
      const content = this.content;
      if (!content) return;

      const msg = {
        from: this.form.username,
        createTime: createTime,
        cmd: 11,
        groupId: 100,
        chatType: 1,
        msgType: 0,
        content: content,
      };
      this.socket.send(JSON.stringify(msg));

      this.content = "";
    },
    // 滚动到底部的方法
    scrollToBottom() {
      this.$nextTick(() => {
        const logDiv = this.$refs.logDiv; // 通过 ref 获取 DOM 元素
        if (logDiv) {
          logDiv.scrollTop = logDiv.scrollHeight; // 滚动到底部
        }
      });
    },
    /**
     * 清空聊天记录
     */
    clearLogs() {
      this.contentList = [];
    },
    /**
     * 展示后台服务配置
     */
    showServerConfig() {
      this.serverConfigVisible = !this.serverConfigVisible;
    },
    setUserName() {
      this.form.username = new Date().getTime().toString();
    },
    /**
     * 鉴权命令
     */
    authCmd() {
      if (!this.curUser) {
        alert("demo中模拟命令需要先登录，请先登录!");
        return;
      }
      const authCmd = {
        cmd: 3,
        token: "校验码",
      };
      this.socket.send(this.gsh(authCmd));
    },
    /**
     * 心跳命令
     */
    heartbeatCmd() {
      if (!this.curUser) {
        alert("demo中模拟命令需要先登录，请先登录!");
        return;
      }
      const heartbeatCmd = {
        cmd: 13,
        hbbyte: "-127",
      };
      this.socket.send(this.gsh(heartbeatCmd));
    },
    /**
     * 查找朋友历史记录
     */
    friendHistoryCmd() {
      if (!this.curUser) {
        this.$message.message("请先登录！");
        return;
      }
      const friend_id = this.historyFriendId;
      if (!friend_id) {
        this.$message.message("请输入要获取的好友ID!");
        return;
      }
      const msgHistoryCmd = {
        cmd: 19,
        type: "1",
        fromUserId: friend_id,
        userId: this.form.username,
      };

      this.socket.send(this.gsh(msgHistoryCmd));
    },
    /**
     * 查找团队历史记录
     */
    groupHistoryCmd() {
      if (!this.curUser) {
        alert("请先登录!");
        return;
      }
      const group_id = this.historyGroupId;
      if (!group_id) {
        alert("请输入要获取的群组ID!");
        return;
      }
      const msgHistoryCmd = {
        cmd: 19,
        type: "1",
        groupId: group_id,
        userId: this.form.username,
      };
      this.socket.send(this.gsh(msgHistoryCmd));
    },
    /**
     *
     * @param obj 鼠标在在线用户悬停事件
     */
    onlineMove(obj) {},
    /**
     *
     * @param obj 鼠标在 在线用户 移除事件
     */
    onlineLeave(obj) {},
    /**
     *
     * @param obj 鼠标点击 在线用户 事件
     */
    onlineDb(obj) {
      /**
       * 目前私发对象
       */
      this.onSelected = obj;
      /**
       * 私发对象名称
       */
      this.sendUser = obj.nick;
    },
    /**
     *
     * @param e 当触发回车键时进行发送到团队接口
     */
    keyDown(e) {
      /**
       * 目前未起效
       */
      var ev = window.event || e;
      //13是键盘上面固定的回车键
      if (ev.keyCode == 13) {
        sendGroup();
      }
    },
    /**
     * json 格式化数据
     */
    gsh(data) {
      return JSON.stringify(data);
    },
    /**
     * 处理系统消息
     */
    doSysmessage(content, time) {
      let message = {
        type: "system",
        content: content,
        time: time,
      };
      this.contentList.push(message);
    },
  },
};
</script>

<style type="text/css" media="screen">
.from {
}
.myContent {
  margin-bottom: 5px;
  padding: 5px;
  /* border: solid 1px #000; */
  height: auto;
  clear: both;
  /* box-sizing: border-box; */
  display: flex;
  background-color: red;
}
.group-name {
  margin-top: 10px;
  font-weight: bold;
}

.user-item {
  line-height: 25px;
  margin: 5px 5px 0 5px;
  padding-left: 15px;
  cursor: pointer;
}

.user-item:hover {
  background: #f0f0f0; /* 鼠标悬停时的背景颜色 */
}

.user-avatar {
  height: 25px;
  width: 25px;
  float: left;
}

.user-info {
  font-size: 12px;
}
* {
  margin: 0;
  padding: 0;
}

#wrap {
  margin: 10px auto;
  width: 80%;
  height: 99%;
}

.unit {
  margin-bottom: 5px;
  padding: 5px;
  border: solid 1px #000;
  height: auto;
  clear: both;
  box-sizing: border-box;
}

.unit label {
  text-align: right;
  width: 100px;
  line-height: 30px;
  display: inline-block;
}

.unit input {
  line-height: 30px;
  width: 100px;
  height: 30px;
}

.log {
  font-size: 11px;
  font-family: Courier;
  overflow: auto;
  height: 100%;
  background: black;
  width: 85%;
  float: left;
}

.log p {
  padding: 2px;
  margin: 0;
}

.content {
  width: 100%;
  /* overflow: hidden; */
  height: 80%;
  display: flex;
  margin: 0 0 5px 0;
}

.online {
  width: 15%;
  height: 100%;
  float: right;
  background: #fcfcfc;
  border: solid 1px #000;
  box-sizing: border-box;
}

/* 样式 */
.chat-container {
  width: 80%;
  padding: 20px;
  background: #f2f2f2;
  overflow-y: auto;
}

/* 系统消息样式 */
.system-message {
  text-align: center;
  margin: 10px 0;
}
.system-content {
  display: inline-block;
  padding: 4px 12px;
  background: #e5e5e5;
  border-radius: 3px;
  color: #666;
  font-size: 12px;
}

/* 历史记录分割线 */
.history-divider {
  display: flex;
  align-items: center;
  margin: 15px 0;
}
.divider-line {
  flex: 1;
  height: 1px;
  background: #ddd;
}
.divider-text {
  padding: 0 10px;
  color: #999;
  font-size: 12px;
}

/* 聊天消息通用样式 */
.bubble-wrapper {
  display: flex;
  margin: 15px 0;
}
.avatar {
  width: 40px;
  height: 40px;
  border-radius: 5px;
  overflow: hidden;
}
.avatar img {
  width: 100%;
  height: 100%;
}

/* 他人消息 */
.message-content {
  max-width: 70%;
  margin-left: 10px;
}
.username {
  color: #666;
  font-size: 12px;
  margin-bottom: 5px;
}
.message-bubble {
  position: relative;
  background: #fff;
  border-radius: 5px;
  padding: 8px 12px;
  min-height: 40px;
}
.message-bubble::before {
  content: "";
  position: absolute;
  left: -8px;
  top: 12px;
  border: 8px solid transparent;
  border-right-color: #fff;
}

/* 自己消息 */
.self-message {
  flex-direction: row-reverse;
}
.self-message .message-content {
  margin-left: 0;
  margin-right: 10px;
}
.self-message .message-bubble {
  background: #9eea6a;
}
.self-message .message-bubble::before {
  left: auto;
  right: -8px;
  border-right-color: transparent;
  border-left-color: #9eea6a;
}

/* 时间戳 */
.time-stamp {
  text-align: right;
  color: #999;
  font-size: 12px;
  margin-top: 5px;
}
</style>